package com.cloud.mkz.core.common.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import lombok.experimental.UtilityClass;

@UtilityClass
public class Md5Util {
	public String bufferToHex(byte[] byteArray) {
	      // 首先初始化一个字符数组，用来存放每个16进制字符
	      char[] hexDigits = {'0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F' };
	      // new一个字符数组，这个就是用来组成结果字符串的（解释一下：一个byte是八位二进制，也就是2位十六进制字符（2的8次方等于16的2次方））
	      char[] resultCharArray =new char[byteArray.length * 2];
	      // 遍历字节数组，通过位运算（位运算效率高），转换成字符放到字符数组中去
	      int index = 0;
	      for (byte b : byteArray) {
	         resultCharArray[index++] = hexDigits[b>>> 4 & 0xf];
	         resultCharArray[index++] = hexDigits[b& 0xf];
	      }
	      // 字符数组组合成字符串返回
	      return new String(resultCharArray);
	}
	
	
	public String getFileMD5String(File file) throws Exception {
		MessageDigest messagedigest = MessageDigest.getInstance("MD5");
		FileInputStream in = new FileInputStream(file);
		FileChannel ch = in.getChannel();
		ByteBuffer bb = ByteBuffer.allocate(4096);
		
		while (ch.read(bb) != -1) {
			bb.flip();
			messagedigest.update(bb);
			bb.clear();
		}

		String md5 = bufferToHex(messagedigest.digest());
		System.gc();
		System.runFinalization();
		ch.close();
		in.close();
		return md5;
	}
	public String randomWriteInputStreamToFileAndMd5(InputStream inputStream, 
			long saveDataPosition, String fileAbsolutePath) throws Exception {
		MessageDigest messageDigest = MessageDigest.getInstance("MD5");
		RandomAccessFile writeRaf = null;
		try {
			// 建立写流
			File uploadFile = new File(fileAbsolutePath);
			writeRaf = new RandomAccessFile(uploadFile, "rw");
			writeRaf.seek(saveDataPosition);
			// 存放每次读取的字节数
			int len = 0;
			// 读取并写入指定范围的数据
			// 建立缓冲区
			byte[] buffer = new byte[4096];
			BufferedInputStream bi = new BufferedInputStream(inputStream);
			bi.mark(4096);
			// 写入
			while (true) {
				len = bi.read(buffer);
				if (len < 0){
					break;
				}
				// 写入上传的文件的某片断
				writeRaf.write(buffer, 0, len);
				messageDigest.update(buffer, 0, len);
			}
			return bufferToHex(messageDigest.digest());
		} finally {
			if (writeRaf != null) {
				writeRaf.close();
			}
		}
	}
	public String getFileMD5String(File file, long start, long end) throws Exception {
		MessageDigest messagedigest = MessageDigest.getInstance("MD5");
		FileInputStream in = new FileInputStream(file);
		FileChannel ch = in.getChannel();
		MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, start, end - start);
		messagedigest.update(byteBuffer);
		
		String md5 = bufferToHex(messagedigest.digest());
		byteBuffer.clear();
		System.gc();
		System.runFinalization();
		ch.close();
		in.close();
		return md5;
	}
	  /**
	    * 对一段String生成MD5加密信息
	    * @param message 要加密的String
	    * @return 生成的MD5信息
	    */
	   public static String getMD5(String message){
	       try {
	           MessageDigest md = MessageDigest.getInstance("MD5");
	           byte[] b = md.digest(message.getBytes());
	           return bufferToHex(b);
	       } catch (NoSuchAlgorithmException e) {
	           e.printStackTrace();
	           return null;
	       }
	   }
	   
}
